#--coding:utf-8--
# @Time    : 2022/04/25/030 14:00
# @Author  : hakold
# @File    : server.py
# @PROJECT : chatroom_game

from os import times
import socket
import threading
import json
import time
import sys
from traceback import print_tb
from model import explevel_model, logic_model


class Sever:
    def __init__(self, URL, PORT):
        self.online_User_pool = {} # 存放在线用户字典{addr:name}
        self.serve_socket_pool = {} # 存放{socket:不同线程的套接字}
        self.online_num = 0 # 在线用户数量
        self.serve_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建socket对象
        addr = (URL, PORT)
        self.serve_socket.bind(addr)  # 绑定地址和端口
        self.serve_socket.listen(128)
        print('TCP Server on', addr[0], ":",addr[1],"......")
        self.socket_acceptThread(self)
        self.ExpThread_process(self)
        self.run(self)
    
    def run(self):
        flag = True
        while flag:
            try:
                time.sleep(10)
            except KeyboardInterrupt:
                print("结束主线程")
                flag = False

    def socket_acceptThread(self):
        # 一个用来accept socket的线程
        # 防止主线程阻塞
        socket_game_thread = Socket_logic_Thread(self.serve_socket, self.online_User_pool, self.serve_socket_pool, self.online_num)
        socket_game_thread.setDaemon(True)
        socket_game_thread.start()

    def run_client(self):
        # 这个函数在退出时运行一次，以防止因 accept 阻塞而无法退出
        client_socket  = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        server = ('127.0.0.1', 9999)
        try:
            client_socket.connect(server)
            client_socket.close()
        except:
            print(sys.exc_info())
            
    def ExpThread_process(self):
        # 经验线程
        expthread = Exp_Thread(self.online_User_pool)
        # 开启新线程
        expthread.setDaemon(True)
        expthread.start()

class Socket_logic_Thread(threading.Thread):
    def __init__(self, serve_socket, online_User_pool, serve_socket_pool, online_num):
        threading.Thread.__init__(self)
        self.serve_socket = serve_socket # 传进来服务器的socket
        self.online_User_pool = online_User_pool
        self.serve_socket_pool = serve_socket_pool
        self.online_num = online_num
    
    def run(self):
        while True:
            try:
                service_client_socket, addr = self.serve_socket.accept() # 等待接收客户端的连接请求
                print("接收到客户端的连接请求....")
                #为服务器分配线程
                self.online_num = self.online_num + 1
                client_thread = threading.Thread(target=self.chat_logic, args=(service_client_socket, addr), daemon=True) 
                client_thread.start()
                print("聊天室人数：", self.online_num) 
            except ConnectionResetError:
                print('Someone left unexcept.')
                break
            except KeyboardInterrupt:
                break
            except:
                print(sys.exc_info())
    
    def chat_logic(self, service_client_socket, addr):
        #如果addr在user字典里，跳过本次循环
        while True:
            try:
                data = service_client_socket.recv(1024)
                # 等待接收客户端消息存放在2个变量service_client_socket和addr里
                if not addr in self.serve_socket_pool:
                    self.serve_socket_pool[addr] = service_client_socket #将服务器与服务器端口号为addr的套接字放入字典
                if len(data) == 0:
                    #user字典addr键对应的值赋值给变量name
                    try:
                        self.online_User_pool.pop(addr) 
                        self.serve_socket_pool.pop(addr)
                    except:
                        pass
                    self.online_num = self.online_num - 1
                    print("聊天室人数：", self.online_num)
                    break
                else: 
                    data = data.decode('utf-8')
                    data_dict = json.loads(data)
                    logic_result = logic_model.main(self, data_dict)
                    if logic_result[0] == 1:
                        # 发给自己
                        return_data = logic_result[1]
                        self.login_success_pool_add(logic_result, addr, service_client_socket) # 登录成功会返回给自己，判断这个可以看是否登录成功，添加用户进在线列表
                        self.data_send_to_self(return_data, service_client_socket)
                    elif logic_result[0] == 2:
                        # 发给所有人 
                        return_data = logic_result[1]
                        self.data_send_to_all(return_data)
                    else:
                        print(logic_result)

            except ConnectionResetError:
                print(self.online_User_pool)
                try:
                    self.online_User_pool.pop(addr) 
                    self.serve_socket_pool.pop(addr)
                except:
                    pass
                print("客户端断开链接")
                self.online_num = self.online_num - 1
                print("聊天室人数：", self.online_num)
                break

    def data_send_to_self(self, return_data, service_client_socket):
        # 只发给自己
        for scs in self.serve_socket_pool:    
            #从user遍历出address
            if self.serve_socket_pool[scs] == service_client_socket:  
                #发送data到客户端
                self.serve_socket_pool[scs].send(return_data.encode('utf-8'))
    
    def data_send_to_all(self, return_data):
        # 发给所有人
        for scs in self.serve_socket_pool:    
            #从user遍历出address
            #发送data到客户端
            self.serve_socket_pool[scs].send(return_data.encode('utf-8'))
    
    def login_success_pool_add(self, logic_result, addr, service_client_socket):
        if "login_success" in logic_result:
        # 登录成功逻辑
            if not addr in self.online_User_pool:
                # 将玩家加入在线列玩家列表
                return_data = logic_result[1]
                print(type(return_data))
                return_data = json.loads(return_data)
                return_data = return_data['data']
                # 如果对应ip地址不在用户user字典里则执行以下代码
                self.online_User_pool[addr] = return_data["account"] #data 是最新进入聊天室的客户，解压后放入user
                self.serve_socket_pool[addr] = service_client_socket #将服务器与服务器端口号为addr的套接字放入字典

    def data_send_to_user(self, return_data, account):
        # 只发给自己
        client_link = 0
        for user_link in self.online_User_pool:
            if self.online_User_pool[user_link] == account:
                client_link = user_link
        for socket_link in self.serve_socket_pool:
            print(socket_link,client_link)
            if socket_link == client_link:
                # 匹配玩家账户名
                #发送data到客户端
                self.serve_socket_pool[socket_link].send(return_data.encode('utf-8'))
    

class Exp_Thread(threading.Thread):
    def __init__(self, online_User_pool):
        threading.Thread.__init__(self)
        self.online_User_pool = online_User_pool
        
    def run(self):
        while True:
            try:
                self.exp_auto_up()
            except:
                print(sys.exc_info())
            time.sleep(5)

    def exp_auto_up(self):
        # 经验方法
        print(self.online_User_pool)
        for eachuser in self.online_User_pool:
            account = self.online_User_pool[eachuser]
            print(account)
            explevel_model.exp_auto_up(account)

class Server_Sender_Thread(threading.Thread):
    def __init__(self, online_User_pool, serve_socket_pool):
        threading.Thread.__init__(self)
        self.online_User_pool = online_User_pool
        self.serve_socket_pool = serve_socket_pool
  
    def send_to_account(self, account, message):
        # 服务器主动方法
        print(account, message)
        print(self.online_User_pool)
        print(self.serve_socket_pool)



if __name__ == '__main__':
    server = Sever
    server.__init__(server, "127.0.0.1", 9999)

